/*
 * =====================================================================================
 *
 *       Filename:  LinkedList.cc
 *
 *    Description:  
 *
 *
 *        Version:  1.0
 *        Created:  03/06/11 16:54:12
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Marco Beierer (mk), marco.beierer@gmail.com
 *        Company:  Saxion Student
 *
 * =====================================================================================
 */

#include "LinkedList.h"
#include <iostream>
#include <cassert>

LinkedList::LinkedList(int size) {
    assert(size > 0);
    header = new ListNode(new Area(0, size));
}

LinkedList::~LinkedList() {
    // list nodes are removed with function clear
    delete header;
}

bool LinkedList::merge(const Area* area) {
    assert(header != 0);
    assert(area != 0);

    bool area_beforeHeader = area->getEnd() + 1 == header->getArea()->getBase();
    bool area_afterHeader = header->getArea()->getEnd() + 1 == area->getBase();

    if (area_beforeHeader || area_afterHeader) {
        ListNode* header_old = header;
        const Area* header_oldArea = header_old->getArea();

        header = header->getNext();

        if (area_beforeHeader) {
            insert(new Area(area->getBase(), area->getSize() + header_oldArea->getSize()));
        }
        else {
            insert(new Area(header_oldArea->getBase(), header_oldArea->getSize() + area->getSize()));
        }
        
        delete header_oldArea;
        header_oldArea = 0;

        delete header_old;
        header_old = 0;

        return true;
    }
    
    return header->merge(area);
}

void LinkedList::insert(const Area* area) {
    assert(area != 0);

    // controleer of er een element in de lijst is
    if (header == 0) {
        header = new ListNode(area);
    }
    // controleer of area is mergeable with an existing hole en delete old area
    else if (merge(area)) {
        delete area;
    }
    // is de size van de area kleiner dan die van de header? dan wordt area het eerste element van de lijst
    else if (area->getSize() <= header->getArea()->getSize()) {
        ListNode* header_new = new ListNode(area);
        header_new->setNext(header);

        header = header_new;
    }
    // mag je het niet toevoegen dan start een recursieve call bij de header
    else {
        header->insert(area);
    }
}

const Area* LinkedList::getBestFittedHole(int size) {
    assert(size > 0);

    // controleer of er een start element is
    if (header == 0) {
        return 0;
    }
    // als groote kleiner dan de header groote is dan verwijder de header node en return de area
    else if (size <= header->getArea()->getSize()) {
        const Area* area = header->getArea();
        ListNode* header_new = header->getNext();

        delete header;
        header = header_new;

        return area;
    }
    // anders start de zoek met een recursieve call
    else {
        return header->getBestFittedHole(size);
    }
}

void LinkedList::clear() {
    if (header != 0) {
        header->deleteNext();
    }
}
